﻿using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace AutoCadConvert
{
    public class Line : BspObject,ICloneable
    {
        public Point V0;//起点
        public Point V1;//终点
        public double Thickness = 120;//厚度 default = 12
        public double Height = 2800;//高度 default = 280
        public double AlignWay = 2;//对齐方式有三种 0:外部对齐， 1：内部对齐， 2：中心对齐， default = 2， 注：直线有厚度
        public double OffsetX = 0;////偏移值， 与AlignWay 关联
        public double OffsetY = 0;//偏移值， 与AlignWay 关联
        public bool IsMainWall = false;//是否为承重墙
        public bool IsLogicLine = false;
        public Curve m_Entity;

        public Line(bool isLogic=false) { IsLogicLine = isLogic; }
        public Line(Line line)
        {
            this.V0 = new Point(line.V0);
            this.V1 = new Point(line.V1);
            this.Thickness = line.Thickness;
            this.Height = line.Height;
            this.AlignWay = line.AlignWay;
            this.OffsetX = line.OffsetX;
            this.OffsetY = line.OffsetY;
            this.m_Entity = line.m_Entity;
            this.IsLogicLine = line.IsLogicLine;
            this.IsMainWall = line.IsMainWall;
        }
        public Line(Autodesk.AutoCAD.DatabaseServices.Line line)
        {
            m_Entity = line;
        }
        public Line(Autodesk.AutoCAD.DatabaseServices.Polyline line)
        {
            m_Entity = line;
        }
        public Line(Point start,Point end)
        {
            V0 = start;
            V1 = end;
        }
        public double Distance
        {
            get { return Math.Sqrt(Math.Pow(this.V0.X-this.V1.X, 2) + Math.Pow(this.V0.Y-this.V1.Y, 2)); }
        }
        public Point Middle
        {
            get { return new Point() { X = V0.X / 2 + V1.X / 2, Y = V0.Y / 2 + V1.Y / 2 }; }
        }
        public override IEnumerable<XElement> ToXml()
        {
            return new XElement[] {
                new XElement("V0",V0.index),
                new XElement("V1",V1.index),
                new XElement("Thickness",Thickness*Unit),
                new XElement("Height",Height*Unit),
                new XElement("AlignWay",AlignWay),
                new XElement("OffsetX",OffsetX*Unit),
                new XElement("OffsetY",OffsetY*Unit),
                new XElement("IsMainWall",IsMainWall?1:0),
                new XElement("IsLogicLine",IsLogicLine?1:0),
            };
        }
        public override IEnumerable<BspObject> FromXml(XElement node)
        {
            int iV0 = Convert.ToInt32(node.Element("V0").Value);
            int iV1 = Convert.ToInt32(node.Element("V1").Value);
            this.Thickness = Convert.ToDouble(node.Element("Thickness").Value);
            this.Height = Convert.ToDouble(node.Element("Height").Value);
            this.AlignWay = Convert.ToDouble(node.Element("AlignWay").Value);
            this.OffsetX = Convert.ToDouble(node.Element("OffsetX").Value);
            this.OffsetY = Convert.ToDouble(node.Element("OffsetY").Value);
            this.IsMainWall = Convert.ToBoolean(node.Element("IsMainWall").Value);
            this.IsLogicLine = Convert.ToBoolean(node.Element("IsLogicLine").Value);
            yield return this;
        }
        public double Cross(Point p1, Point p2, Point p0)//叉乘
        {
            return (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y);
        }
        public double Cross(Line ln)
        {
            Point pt = new Point();
            pt.X = this.V1.X - this.V0.X;
            pt.Y = this.V1.Y - this.V0.Y;
            Point ptl = new Point();
            ptl.X = ln.V1.X - ln.V0.X;
            ptl.Y = ln.V1.Y - ln.V0.Y;
            return (pt.X * ptl.Y - pt.Y * ptl.X);
        }
        public Line Normal()
        {
            Line ln = new Line();
            ln.V0 = new Point();
            ln.V0.X = 0;
            ln.V0.Y = 0;
            double dis = this.Distance;
            Point pt = new Point();
            pt.X = this.V1.X - this.V0.X;
            pt.Y = this.V1.Y - this.V0.Y;
            pt.X = pt.X / dis;
            pt.Y = pt.Y / dis;
            ln.V1 = pt;
            return ln;
        }
        public double Dot(Point p1, Point p2, Point p0)//点积
        {
            return (p1.X - p0.X) * (p2.X - p0.X) + (p2.Y - p0.Y) * (p1.Y - p0.Y);
        }
        public double Dot(Line ln)
        {
            Point pt = new Point();
            pt.X = this.V1.X - this.V0.X;
            pt.Y = this.V1.Y - this.V0.Y;
            Point ptl = new Point();
            ptl.X = ln.V1.X - ln.V0.X;
            ptl.Y = ln.V1.Y - ln.V0.Y;
            return (pt.X * ptl.X + pt.Y * ptl.Y);
        }
        public double DotDistance(Point pt)
        {
            if (this.V1.X != this.V0.X)
            {
                double k = (this.V1.Y - this.V0.Y) / (this.V1.X - this.V0.X);
                double c = this.V1.Y - k * this.V1.X;
                return Math.Abs((pt.Y - k * pt.X - c) / Math.Sqrt(Math.Pow(k,2)+1));
            }
            else
            {
                return Math.Abs(pt.X - this.V0.X);
            }
        }
        public bool isColide(Line line)//判断是否相交,直线p1p2与线段p3p4
        {
            //判处端点
            if (this.V0 == line.V0 || this.V0 == line.V1 || this.V1 == line.V0 || this.V1 == line.V1)
                return false;

            double deviation = 0.1;
            //排斥试验，判断p1p2在q1q2为对角线的矩形区之外
            if (Math.Max(line.V0.X, line.V1.X) < Math.Min(this.V0.X, this.V1.X)- deviation)
            {//P1P2中最大的X比Q1Q2中的最小X还要小，说明P1P2在Q1Q2的最左点的左侧，不可能相交。
                return false;
            }

            if (Math.Min(line.V0.X, line.V1.X) > Math.Max(this.V0.X, this.V1.X)+ deviation)
            {//P1P2中最小的X比Q1Q2中的最大X还要大，说明P1P2在Q1Q2的最右点的右侧，不可能相交。
                return false;
            }

            if (Math.Max(line.V0.Y, line.V1.Y) < Math.Min(this.V0.Y, this.V1.Y)- deviation)
            {//P1P2中最大的Y比Q1Q2中的最小Y还要小，说明P1P2在Q1Q2的最低点的下方，不可能相交。
                return false;
            }

            if (Math.Min(line.V0.Y, line.V1.Y) > Math.Max(this.V0.Y, this.V1.Y)+ deviation)
            {//P1P2中最小的Y比Q1Q2中的最大Y还要大，说明P1P2在Q1Q2的最高点的上方，不可能相交。
                return false;
            }

            //跨立试验
            var crossP1P2Q1 = Cross(line.V0, line.V1, this.V0) / line.Distance / this.Distance;
            var crossP1Q2P2 = Cross(line.V0, this.V1, line.V1) / line.Distance / this.Distance;
            var crossQ1Q2P1 = Cross(this.V0, this.V1, line.V0) / line.Distance / this.Distance;
            var crossQ1P2Q2 = Cross(this.V0, line.V1, this.V1) / line.Distance / this.Distance;

            return (crossP1P2Q1 * crossP1Q2P2 >= 0||Math.Abs(crossP1P2Q1 * crossP1Q2P2)<0.01) 
                && (crossQ1Q2P1 * crossQ1P2Q2 >= 0|| Math.Abs(crossQ1Q2P1 * crossQ1P2Q2) < 0.01);
        }
        public Point getPoint(Line line)//求出交点,直线(线段)p1p2与直线(线段)p3p4
        {//t=lamta/(1+lamta)
            double x1 = this.V0.X, y1 = this.V0.Y;
            double x2 = this.V1.X, y2 = this.V1.Y;
            double x3 = line.V0.X, y3 = line.V0.Y;
            double x4 = line.V1.X, y4 = line.V1.Y;
            double t = ((x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1)) / ((x2 - x1) * (y3 - y4) - (x3 - x4) * (y2 - y1));
            return new Point() { X = x3 + t * (x4 - x3), Y = y3 + t * (y4 - y3), refCount = 1 };
            //double d1 = Math.Abs(Cross(line.V1, this.V0, line.V0));
            //double d2 = Math.Abs(Cross(line.V1, this.V1, line.V0));
            //double t = d1 / (d1 + d2);
            //Point temp = (this.V1 - this.V0) * t;
            //return this.V0 + temp;
        }
        public bool Contain(Point pt)
        {
            if (pt.X<Math.Min(this.V0.X,this.V1.X)|| pt.X > Math.Max(this.V0.X, this.V1.X))
                return false;

            if (pt.Y < Math.Min(this.V0.Y, this.V1.Y) || pt.Y > Math.Max(this.V0.Y, this.V1.Y))
                return false;

            if (Math.Abs(this.V0.Y - pt.Y) / Math.Abs(this.V0.X - pt.X) == Math.Abs(this.V1.Y - pt.Y) / Math.Abs(this.V1.X - pt.X))
                return true;
            else
                return false;
        }
        public Point getSamePoint(Line ln)
        {//两个线的共用端点有交点
            if (this.V0 == ln.V0 || this.V0 == ln.V1)
                return this.V0;
            else if (this.V1 == ln.V0 || this.V1 == ln.V1)
                return this.V1;
            else
                return null;
        }
        public object Clone()
        {//深拷贝
            return new Line(this);
        }
        //public override Type GetType() { return typeof(Line); }
    }
}
